//
#include <types.h>
//
//
#include <defs.h>
//
#include <param.h>
//
#include <memlayout.h>
//
#include <mmu.h>
//
#include <proc.h>
//
#include <x86.h>
//
#include <spinlock.h>
#include <traps.h>
//

// 中断描述符表 (所有 CPU 共享).
struct gatedesc idt[256];
extern uint vectors[];	// in vectors.S: array of 256 entry pointers
struct spinlock tickslock;
uint ticks;
//初始化中断描述符，从vectors复制到idt里面
void tvinit(void) {
	int i;

	for (i = 0; i < 256; i++)
		SETGATE(idt[i], 0, SEG_KCODE << 3, vectors[i], 0);
	SETGATE(idt[T_SYSCALL], 1, SEG_KCODE << 3, vectors[T_SYSCALL], DPL_USER);

	initlock(&tickslock, "time");
}

void idtinit(void) {
	lidt(idt, sizeof(idt));
}

//PAGEBREAK: 41
void trap(struct trapframe *tf) {
	if (tf->trapno == T_SYSCALL) {
		if (myproc()->killed)
			exit();
		myproc()->tf = tf;
		syscall();
		if (myproc()->killed)
			exit();
		return;
	}

	switch (tf->trapno) {
	case T_IRQ0 + IRQ_TIMER:
		if (cpuid() == 0) {
			acquire(&tickslock);
			ticks++;
			wakeup(&ticks);
			release(&tickslock);
		}
		lapiceoi();
		break;
	case T_IRQ0 + IRQ_IDE:
		ideintr();
		lapiceoi();
		break;
	case T_IRQ0 + IRQ_IDE + 1:
		// Bochs generates spurious IDE1 interrupts.
		break;
	case T_IRQ0 + IRQ_KBD:
		kbdintr();
		lapiceoi();
		break;
	case T_IRQ0 + IRQ_COM1:
		uartintr();
		lapiceoi();
		break;
	case T_IRQ0 + 7:
	case T_IRQ0 + IRQ_SPURIOUS:
		cprintf("cpu%d: spurious interrupt at %x:%x\n",
				cpuid(), tf->cs, tf->eip);
		lapiceoi();
		break;
	case T_IRQ0 + IRQ_E1000:
		e1000intr();
		lapiceoi();
		break;

	//PAGEBREAK: 13
	default:
		if (myproc() == 0 || (tf->cs & 3) == 0) {
			// In kernel, it must be our mistake.
			cprintf("unexpected trap %d from cpu %d eip %x (cr2=0x%x)\n",
					tf->trapno, cpuid(), tf->eip, rcr2());
			panic("trap");
		}
		// In user space, assume process misbehaved.
		cprintf(
			"pid %d %s: trap %d err %d on cpu %d "
			"eip 0x%x addr 0x%x--kill proc\n",
			myproc()->pid, myproc()->name, tf->trapno,
			tf->err, cpuid(), tf->eip, rcr2());
		myproc()->killed = 1;
	}

	// Force process exit if it has been killed and is in user space.
	// (If it is still executing in the kernel, let it keep running
	// until it gets to the regular system call return.)
	if (myproc() && myproc()->killed && (tf->cs & 3) == DPL_USER)
		exit();

	// Force process to give up CPU on clock tick.
	// If interrupts were on while locks held, would need to check nlock.
	if (myproc() && myproc()->state == RUNNING &&
		tf->trapno == T_IRQ0 + IRQ_TIMER)
		yield();

	// Check if the process has been killed since we yielded
	if (myproc() && myproc()->killed && (tf->cs & 3) == DPL_USER)
		exit();
}
